/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.velocityme.session;

import com.velocityme.entity.Activity;
import com.velocityme.entity.ChangeDelta;
import com.velocityme.entity.Contactable;
import com.velocityme.entity.Node;
import com.velocityme.entity.Person;
import com.velocityme.entity.RootNode;
import com.velocityme.entity.Sprint;
import com.velocityme.enums.ChangeDeltaItemType;
import com.velocityme.enums.ChangeDeltaType;
import com.velocityme.enums.Permission;
import com.velocityme.session.NodeLocal.SummaryTables;
import com.velocityme.utility.DurationRemaining;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 *
 * @author rcrida
 */
@Stateless
public class SprintBean implements SprintLocal {
    @EJB
    private NodeLocal nodeBean;

    @PersistenceContext
    private EntityManager em;

    @Override
    public Sprint findSprint(KeyLocal key, Long sprintId) {
        Sprint sprint = em.find(Sprint.class, sprintId);
        key.assertHasPermission(sprint, Permission.NODE_VIEW);
        return sprint;
    }

    public Sprint createSprint(KeyLocal key, Sprint sprint) {
        key.assertHasPermission(sprint.getParentNode(), Permission.SPRINT_CREATE);
        ChangeDelta changeDelta = sprint.addChangeDelta(ChangeDeltaType.CREATE, key.getUser());
        nodeBean.logCreate(sprint, changeDelta);
        changeDelta.addItem(ChangeDeltaItemType.SCRUM_MASTER, sprint.getScrumMaster().toString());
        for (Person person: sprint.getTeamMembers()) {
            changeDelta.addItem(ChangeDeltaItemType.ADD_TEAM_MEMBER, person.toString());
        }
        em.persist(sprint);
        em.persist(changeDelta);
        return sprint;
    }

    public void editSprint(KeyLocal key, Sprint sprint) {
        Sprint current = em.find(Sprint.class, sprint.getId());
        key.assertHasPermission(sprint, Permission.GROUP_EDIT);
        ChangeDelta changeDelta = sprint.addChangeDelta(ChangeDeltaType.EDIT, key.getUser());
        nodeBean.logEdit(sprint, current, changeDelta);
        if (!sprint.getScrumMaster().equals(current.getScrumMaster())) {
            changeDelta.addItem(ChangeDeltaItemType.SCRUM_MASTER, sprint.getScrumMaster().toString());
        }
        // check users
        Collection<Person> teamRemoved = new ArrayList<Person>(current.getTeamMembers());
        teamRemoved.removeAll(sprint.getTeamMembers());
        Collection<Person> teamAdded = new ArrayList<Person>(sprint.getTeamMembers());
        teamAdded.removeAll(current.getTeamMembers());
        for (Person person: teamRemoved) {
            changeDelta.addItem(ChangeDeltaItemType.REMOVE_TEAM_MEMBER, person.toString());
        }
        for (Person person: teamAdded) {
            changeDelta.addItem(ChangeDeltaItemType.ADD_TEAM_MEMBER, person.toString());
            em.merge(person);
        }
        em.persist(changeDelta);
        em.merge(sprint);
    }

    public Map<Activity,DurationRemaining> searchProgressSum(KeyLocal key, Sprint sprint) {
        Map<Activity,DurationRemaining> results = new TreeMap<Activity,DurationRemaining>(new Comparator<Activity>() {
            public int compare(Activity t1, Activity t2) {
                String n1 = t1.getProjectPathName() + t1.getName();
                String n2 = t2.getProjectPathName() + t2.getName();
                return n1.compareTo(n2);
            }
        });
        Date start = sprint.getStartDate();
        Date stop = sprint.getStopDate();
        for (Node node: nodeBean.getLinkedNodes(key, sprint)) {
            if (node instanceof Activity) {
                Activity activity = (Activity)node;
                DurationRemaining dr = nodeBean.searchDurationSum(key, node, true, true, start, stop, true).get("-");
                results.put(activity, dr);
            }
        }
        return results;
    }

    public Map<String,DurationRemaining> searchDurationSum(KeyLocal key, Sprint sprint) {
        Map<String,DurationRemaining> results = new TreeMap<String,DurationRemaining>();
        Date start = sprint.getStartDate();
        Date stop = new Date();
        // get the earlier of now or the end of sprint
        if (stop.after(sprint.getStopDate()))
            stop = sprint.getStopDate();
        for (Node node :nodeBean.getLinkedNodes(key, sprint)) {
            addSearch(results, nodeBean.searchDurationSum(key, node, false, true, start, stop, false));
        }
        addSearch(results, nodeBean.searchUnplannedSum(key, sprint.getTeamMembers(), true, start, stop, false));
        return results;
    }

    private void addSearch(Map<String,DurationRemaining> map, Map<String,DurationRemaining> search) {
        if (map.isEmpty()) {
            map.putAll(search);
        }
        else {
            for (Map.Entry<String,DurationRemaining> entry: search.entrySet()) {
                DurationRemaining dr = map.get(entry.getKey());
                dr.add(entry.getValue());
            }
        }
    }

    public Map<String,Object> getSearchTimeLog(KeyLocal key, Sprint sprint) {
        Collection<Contactable> contactables = new ArrayList<Contactable>();
        for (Person person: sprint.getTeamMembers()) {
            contactables.add(person);
        }
        RootNode rootNode = (RootNode) em.createNamedQuery("findRootNode").getSingleResult();
        Set<SummaryTables> summaries = new HashSet<SummaryTables>();
        summaries.add(SummaryTables.DAY);
        return nodeBean.searchTimeLogValue(key, rootNode, contactables, true, summaries, sprint.getStartDate(), sprint.getStopDate());
    }
    
    public Map<String,Object> getUnplannedSearchTimeLog(KeyLocal key, Sprint sprint) {
        Collection<Contactable> contactables = new ArrayList<Contactable>();
        for (Person person: sprint.getTeamMembers()) {
            contactables.add(person);
        }
        RootNode rootNode = (RootNode) em.createNamedQuery("findRootNode").getSingleResult();
        Set<SummaryTables> summaries = new HashSet<SummaryTables>();
        summaries.add(SummaryTables.TASK);
        return nodeBean.searchTimeLogFilteredValue(key, rootNode, nodeBean.getLinkedNodes(key, sprint), contactables, true, summaries, sprint.getStartDate(), sprint.getStopDate());
    }


}
